package top.jiangqiang.qyblog.core.config;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.router.SaRouterStaff;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.jiangqiang.qyblog.common.base.response.Result;
import top.jiangqiang.qyblog.common.config.GlobalProperties;
import top.jiangqiang.qyblog.common.constant.RequestURLConstants;
import top.jiangqiang.qyblog.common.constant.ResponseEnum;
import top.jiangqiang.qyblog.core.domain.entity.Storage;
import top.jiangqiang.qyblog.core.service.IAdminUserService;
import top.jiangqiang.qyblog.core.service.IConfigService;
import top.jiangqiang.qyblog.core.service.IStorageService;

import java.util.Arrays;
import java.util.Map;

/**
 * @author Jiangqiang
 */
@Configuration
//@EnableWebMvc//会导致WebMvcAutoConfiguration失效
@RequiredArgsConstructor
public class QyWebMvcConfigurer implements WebMvcConfigurer {
    private final GlobalProperties globalProperties;
    private final IAdminUserService adminUserService;
    private final IConfigService configService;
    private final IStorageService storageService;

    /**
     * 跨域配置
     */
//    @Bean
//    public CorsFilter corsFilter() {
//        CorsConfiguration config = new CorsConfiguration();
//        config.setAllowCredentials(true);
//        // 设置访问源地址
//        config.addAllowedOriginPattern("*");
//        // 设置访问源请求头
//        config.addAllowedHeader("*");
//        // 设置访问源请求方法
//        config.addAllowedMethod("*");
//        // 有效期 1800秒
//        config.setMaxAge(1800L);
//        // 添加映射路径，拦截一切请求
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", config);
//        // 返回新的CorsFilter
//        return new CorsFilter(source);
//    }

//    /**
//     * 如果需要自定义消息转换器并且需要修改转换器优先级，可以重写此方法
//     *
//     * @param converters 自动初始化的转换器
//     */
//    @Override
//    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//
//    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        GlobalProperties.FileConfig fileConfig = globalProperties.getFileConfig();
        if (fileConfig == null) {
            return;
        }
        Map<String, String> staticResourceMapping = fileConfig.getStaticResourceMapping();
        if (CollUtil.isNotEmpty(staticResourceMapping)) {
            //path：访问路径 resourceLocationStr：一个或多个资源位置通过逗号拼接的字符串
            staticResourceMapping.forEach((path, resourceLocationStr) -> {
                String[] resourceLocations = Arrays.stream(resourceLocationStr.split(",")).filter(StrUtil::isNotBlank).map(resourceLocation -> {
                    resourceLocation = resourceLocation.trim();
                    if (resourceLocation.startsWith("file:") || resourceLocation.startsWith("classpath:")) {
                        return resourceLocation;
                    } else {
                        return "file:" + resourceLocation;
                    }
                }).toArray(String[]::new);
                registry.addResourceHandler(path.replaceAll("//", "/")).addResourceLocations(resourceLocations);
            });
        }
    }

    /**
     * sa-token拦截器不会拦截静态资源
     * 注册路由拦截器，自定义认证规则
     *
     * @param registry InterceptorRegistry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SaInterceptor(handler -> {
            // 初始化校验================start================
//            SaRouter.match("/admin/**")
//                    .notMatch("/admin/user/**")
//                    .notMatch("/admin/config/**")
//                    .notMatch("/admin/storage/**")
//                    .check(r -> {
//                        /* 强制注册用户，访问后台接口时，如果没有注册账户则必须注册 */
//                        if (adminUserService.count() == 0) {
//                            r.back(Result.build(ResponseEnum.ADMINISTRATOR_ACCOUNT_WAS_NOT_INITIALIZED));
//                        }
////                        /*强制配置博客基础信息*/
////                        BlogConfig blogConfig = configService.getConfig(ConfigKey.BLOG_CONFIG);
////                        if (blogConfig == null) {
////                            r.back(Result.build(ResponseEnum.BLOG_CONFIG_WAS_NOT_INITIALIZED));
////                        }
//                    });

            SaRouter.match(RequestURLConstants.ARTICLE_CONTROLLER_PREFIX + "/saveOrUpdate").check(r -> {
                //编写文章时，自动对token续期，保证token不会失效
                StpUtil.renewTimeout(3600);
            });

            //文件操作相关接口
            SaRouter.match(RequestURLConstants.FILE_CONTROLLER_PREFIX + "/**")
                    .check(r -> {
                        //如果不存在可用的存储器，则无法使用文件操作接口
                        Storage activeStorage = storageService.getActiveStorage();
                        if (activeStorage == null) {
                            r.back(Result.build(ResponseEnum.STORAGE_CONFIG_WAS_NOT_INITIALIZED));
                        }
                    });
            // 初始化校验================end================

            // 登录校验，拦截所有后台路由
            SaRouterStaff adminRouterStaff = SaRouter.match("/admin/**");
            //不拦截允许匿名访问的接口
            for (String path : globalProperties.getSecurity().getAllowAnonymousAccess()) {
                adminRouterStaff.notMatch(path);
            }
            adminRouterStaff.check(r -> StpUtil.checkLogin());


            // 角色校验 -- 拦截以 admin 开头的路由，必须具备 admin 角色或者 super-admin 角色才可以通过认证
//            SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));

            // 权限校验 -- 不同模块校验不同权限
//            SaRouter.match("/public/**", r -> StpUtil.checkPermission("user"));

        })).addPathPatterns("/**");

    }

}